package com.mt.repair.service.repairManagement.impl;

import com.mt.common.core.utils.QrCodeUtil;
import com.mt.common.core.utils.ScheduledUtils;
import com.mt.common.core.utils.StringUtils;
import com.mt.repair.dao.repairManagement.DeviceDao;

import com.mt.common.core.exception.BusinessException;
import com.mt.common.core.web.base.PageDTO;
import com.mt.common.core.web.base.PageResultDTO;
import com.mt.common.core.web.base.BaseEntity;
import com.mt.common.core.web.BaseService;
import com.mt.repair.utils.GetSerialNum;
import com.mt.repair.utils.ServiceName;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.mt.repair.entity.repairManagement.Device;
import com.mt.repair.service.repairManagement.DeviceService;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Service
@Transactional
public class DeviceServiceBean extends BaseService implements DeviceService {

    private static Logger logger = LogManager.getLogger();

	@Autowired
	private DeviceDao deviceDao;

	@Resource
	private RedisTemplate<String, List<Device>> redisTemplate;

	@Autowired
	StringRedisTemplate stringRedisTemplate;

	/**
	 * 根据分页参数查询设备集合
	 *
	 * @param pageDTO 分页条件
	 */
	@Override
	public PageResultDTO findDevices(PageDTO pageDTO){
        pageDTO.setStartIndex((pageDTO.getCurrentPage()-1)*pageDTO.getPageSize());
		//TODO:请在此校验参数的合法性
		this.validateFindDevices(pageDTO);
		List<Device> deviceDTOS = this.deviceDao.findDevices(pageDTO);
		Long totalCount = this.deviceDao.findDeviceTotalCount(pageDTO);

		PageResultDTO pageResultDTO = new PageResultDTO();
		pageResultDTO.setTotalCount(totalCount);
		pageResultDTO.setDatas(deviceDTOS);

		return pageResultDTO;
	}

	/**
	 * 查询全部设备集合
	 *
	 */
	@Override
	public List<Device> findAllDevices(){
		return this.deviceDao.findAllDevices();
	}

	/**
	 * 查询所有设备集合(只提取ID 和 Name)
	 *
	 */
	@Override
	public List<Device> findAllDevicesWithIdName(){
		//TODO:请在此校验参数的合法性
		this.validateFindAllDevicesWithIdName();
		return this.deviceDao.findAllDevicesWithIdName();
	}

	/**
	 * 根据名称查询设备集合(只提取ID 和 Name)
	 *
	 * @param deviceName 名称
	 */
	@Override
	public List<Device> findDevicesWithIdNameByName(String deviceName){
		//TODO:请在此校验参数的合法性
		this.validateFindDevicesWithIdNameByName(deviceName);
		//TODO:缓存取对应参数
		Set<String> keys = stringRedisTemplate.keys("searchData:Device_where_deviceName_" + deviceName);
		List<Device> devices = new ArrayList<>();
		if (keys.isEmpty()) {
		devices = this.deviceDao.findDevicesWithIdNameByName(deviceName);
		redisTemplate.opsForValue().set("searchData:Device_where_deviceName_" + deviceName, devices, 30, TimeUnit.DAYS);
		} else {
		devices = redisTemplate.opsForValue().get("searchData:Device_where_deviceName_" + deviceName);
		}
		return devices;
	}

	/**
	 * 根据ID查询指定的设备(只提取ID 和 Name)
	 *
	 * @param deviceId Id
	 */
	@Override
	public Device findDevicesWithIdNameById(Long deviceId){
		//TODO:请在此校验参数的合法性
		this.validateFindDevicesWithIdNameById(deviceId);
		return this.deviceDao.findDevicesWithIdNameById(deviceId);
	}

	/**
	 * 根据ID查询指定的设备
	 *
	 * @param deviceId Id
	 */
	@Override
	public Device findDevice(Long deviceId){
		//TODO:请在此校验参数的合法性
		this.validateFindDevice(deviceId);
		return this.deviceDao.findDevice(deviceId);
	}

	/**
	 * 根据ID查询指定的设备(包含外键)
	 *
	 * @param deviceId Id
	 */
	@Override
	public Device findDeviceWithForeignName(Long deviceId){
		//TODO:请在此校验参数的合法性
		this.validateFindDeviceWithForeignName(deviceId);
		return this.deviceDao.findDeviceWithForeignName(deviceId);
	}

	/**
	 * 新增设备
	 *
	 * @param device 实体对象
	 */
	@Autowired
	private GetSerialNum getSerialNum;
	@Override
	public Device saveDevice(Device device) throws IOException {
		//TODO:请在此校验参数的合法性
		this.validateSaveDevice(device);
		//TODO:填充公共参数
		this.setSavePulicColumns(device);
		//生成编号
		device.setDeviceCode("DE"+ getSerialNum.getSerialNum(GetSerialNum.deviceLock,GetSerialNum.deviceNum,5));
		//生成二维码
		String qrCode = QrCodeUtil.crateQRCodeBase64("deviceCode:" + device.getDeviceCode(), 100, 100);
		device.setQrCode(qrCode);
		Long rows = this.deviceDao.saveDevice(device);
		if(rows != 1)
		{
			String error = "新增保存设备出错，数据库应该返回1,但返回了 "+rows;
			throw new BusinessException(error);
		}
		return device;
	}

	/**
	 * 更新设备
	 *
	 * @param device 实体对象
	 */
	@Override
	public Device updateDevice(Device device){
		//TODO:请在此校验参数的合法性
		this.validateUpdateDevice(device);
		Long rows = this.deviceDao.updateDevice(device);
		if(rows != 1)
		{
			String error = "修改保存设备出错，数据库应该返回1,但返回了 "+rows+",数据可能被删除";
			throw new BusinessException(error);
		}
		return device;
	}

	@Override
	public List<Device> findDevicesByUser(Long userId) {
		if(userId==null){
			userId=this.getLoginUserId();
		}
		return this.deviceDao.findDevicesByUser(userId);
	}

	@Override
	public Device findDeviceByCode(String deviceCode) {
		return this.deviceDao.findDeviceByCode(deviceCode);
	}

	/**
	 * 根据ID删除设备
	 *
	 * @param deviceId ID
	 */
	@Override
	public void deleteDevice(Long deviceId){
		//TODO:请在此校验参数的合法性
		this.validateDeleteDevice(deviceId);

		Map<Class<? extends BaseEntity>,EntityUsage> entityUsageMap = this.checkForeignEntity(Device.class, deviceId);
		if(entityUsageMap != null && entityUsageMap.size() >0){
			StringBuilder errors = new StringBuilder();
			errors.append("计划删除的数据正在被以下数引用\n");
			for(EntityUsage entityUsage : entityUsageMap.values()){
				errors.append("\t").append(entityUsage.getEntityLabel()).append("\n");
				for(Map.Entry<Long,String> entry : entityUsage.getUsageIdNames().entrySet() ){
					errors.append("\t\t").append(entry.getKey()).append("\t").append(entry.getValue()).append("\n");
				}
			}
			errors.append("，不能删除，请检查处理后再删除");
			throw  new BusinessException(errors.toString());
		}

		Long rows = this.deviceDao.deleteDevice(deviceId);
		if(rows != 1){
			String error = "删除设备出错，数据可能已经被删除";
			throw new BusinessException(error);
		}
	}

	//TODO:---------------验证-------------------

	private void validateFindDevices(PageDTO pageDTO) {
	//TODO:请使用下面方法添加数据过滤条件
	//		pageDTO.addFilter("creatorId",this.getLoginUserId());
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateDevice()写法
	}

	private void validateFindDevicesWithIdNameByName(String deviceName) {
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateDevice()写法
	}


	private void validateFindAllDevicesWithIdName() {
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateDevice()写法
	}

	private void validateFindDevicesWithIdNameById(Long deviceId) {
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateDevice()写法
	}

	private void validateFindDevice(Long deviceId) {
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateDevice()写法
	}

	private void validateFindDeviceWithForeignName(Long deviceId) {
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateDevice()写法
	}

	private void validateSaveDevice(Device device) {
	//不为空判断
	if (device.getEid() != null || device.getCreatorId() != null || device.getCreateDatetime() != null) {
	throw new BusinessException("非法请求");
	}
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateDevice()写法
	}

	private void validateUpdateDevice(Device device) {
	//不为空判断
	if (device.getEid() == null) {
	throw new BusinessException("唯一标识不能为空");
	}
	//是否存在判断
	if (this.deviceDao.findDeviceTotalCount(PageDTO.create(Device.FIELD_ID, device.getEid())) == 0) {
	throw new BusinessException("修改的设备 " + device.getName() + " 不存在，修改失败，请重试或联系管理员");
	}
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateDevice()写法
	}

	private void validateDeleteDevice(Long deviceId) {
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateDevice()写法
	}

	@Override
	public boolean canDownloadAttachment(String formName, Long id) {
	return true;
	}

	//@Override
	//public void afterPropertiesSet() throws Exception {
	//	DeviceService deviceService=this;
	//	String name=deviceService.getClass().getSimpleName();
	//	Method[] declaredMethods = this.getClass().getDeclaredMethods();
	//	List<String> res=new ArrayList<>();
	//	for (int i = 0; i < declaredMethods.length; i++) {
	//		res.add(declaredMethods[i].getName());
	//	}
	//	char[] cs=name.toCharArray();
	//	cs[0]+=32;
	//	name=new String(cs);
	//	ScheduledUtils.serviceMap.put(name,res);
	//}
}
